﻿"use strict";

//Define Namespace
window.ArthurGraus = window.ArthurGraus || {};

var odataQueryBuilder;

$(document).ready(function () {
    odataQueryBuilder = new ArthurGraus.ODATAQueryBuilder();
    odataQueryBuilder.initialize();

    ko.applyBindings(odataQueryBuilder);
});


ArthurGraus.ODATAQueryBuilder = function () {
    var self = this;

    self.appWebUrl = "";
    self.hostWebUrl = "";
    self.context = null;
    self.contextHostWeb = null;
    self.executor = null;
    self.availableSortMethods = [
        { value: "asc", title: "Asc" },
        { value: "desc", title: "Desc" }
    ];
    self.operators = [
        { value: "gt", title: ">" },
        { value: "ge", title: ">=" },
        { value: "lt", title: "<" },
        { value: "le", title: "<=" },
        { value: "ne", title: "<>" },
        { value: "eq", title: "==" },
        { value: "substringof", title: "contains" }

    ];
    self.queryStringFromAppWeb = "";
    self.top = ko.observable("100");
    self.skip = ko.observable("");
    self.format = ko.observable("json");
    self.results = ko.observable("-");

    self.availableFields = ko.observableArray();
    self.selectedFields = ko.observableArray();
    self.orderByFields = ko.observableArray();
    self.filters = ko.observableArray();

    self.initialize = function () {

        $('#select').hide();


        $('#btnAdd').click(self.btnAdd_click);
        $('#btnRemove').click(self.btnRemove_click);
        $('#selLists').change(self.selLists_changed);
        $("#ulAvailableFields").selectable();
        $("#ulSelectedFields").selectable();

        self.appWebUrl = decodeURIComponent(getQuerystring("SPAppWebUrl"));
        self.hostWebUrl = decodeURIComponent(getQuerystring("SPHostUrl"));

        self.executor = new SP.RequestExecutor(self.appWebUrl);
        self.executor.executeAsync(
            {
                url:
                    self.appWebUrl +
                    "/_api/SP.AppContextSite(@target)/web/lists?@target='" +
                    self.hostWebUrl + "'",
                method: "GET",
                headers: { "Accept": "application/json; odata=verbose" },
                success: self.getLists_completed,
                error: self.errorHandler
            }
        );

    };

    self.getLists_completed = function (data) {
        var lists = JSON.parse(data.body).d.results;

        $('#selLists').append(
                        $('<option></option>').val(-1).html("CHOOSE LIST")
            );

        $.each(lists, function (index) {

            $('#selLists').append(
                        $('<option></option>').val(lists[index].Id).html(lists[index].Title)
            );

        });
    };

    self.selLists_changed = function () {
        self.executor.executeAsync(
        {
            url:
                self.appWebUrl +
                "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('" + $("#selLists option:selected").text() + "')" +
                                                   "/fields/?@target='" + self.hostWebUrl + "'" +
                                                "&$select=Title,Id,InternalName,TypeAsString" +
                                                "&filter=Hidden%20eq%20False" +
                                                "&$orderby=InternalName%20asc",
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: self.getColumns_completed,
            error: self.errorHandler
        }
        );


    };

    self.getColumns_completed = function (data) {
        var columns = JSON.parse(data.body).d.results;

        self.clearAll();

        $.each(columns, function (index) {

            if (columns[index].InternalName.indexOf('_') != 0) {
                if (self.isSupportedFieldType(columns[index].TypeAsString)) {

                    $('#ulAvailableFields').append(
                                $('<li></li>').attr(
                        "internalname", columns[index].InternalName).attr(
                        "id", "field_" + columns[index].InternalName).attr(
                                "type", columns[index].TypeAsString
                                ).html(
                        columns[index].InternalName + ' (' + columns[index].TypeAsString + ')')
                    );

                    self.availableFields.push(new field(columns[index].InternalName, columns[index].Title, columns[index].TypeAsString));
                }
            }
        });


        $('#select').show();

    };

    self.clearAll = function () {
        $('#ulAvailableFields').empty();
        $('#ulSelectedFields').empty();

    };

    self.btnAdd_click = function () {

        var selectedListItems = $('#ulAvailableFields li.ui-selected');
        var selectedListItem;
        var internalName;
        var type;

        $.each(selectedListItems, function (index) {
            selectedListItem = $('#' + selectedListItems[index].id);
            internalName = selectedListItem.attr("internalname");
            type = selectedListItem.attr("type");

            $('#ulSelectedFields').append(
            $('<li></li>').attr(
                            "internalname", internalName).attr(
                                "id", "selectedField_" + internalName).attr(
                                "type", type
                                ).html(
                                    selectedListItems[index].innerHTML)
);
            selectedListItem.remove();
            self.selectedFields.push(new field(internalName, selectedListItems[index].innerHTML, type));

        });
    };

    self.btnRemove_click = function () {
        var selectedListItems = $('#ulSelectedFields li.ui-selected');
        var selectedListItem;
        var internalName;
        var type;

        $.each(selectedListItems, Function.createDelegate(self, function (index) {
            selectedListItem = $('#' + selectedListItems[index].id);
            internalName = selectedListItem.attr("internalname");
            type = selectedListItem.attr("type");

            $('#ulAvailableFields').append(
            $('<li></li>').attr(
                            "internalname", internalName).attr(
                                "id", "field_" + internalName).attr(
                                "type", type
                                ).html(
                                    selectedListItems[index].innerHTML)
);
            selectedListItem.remove();
            self.selectedFields.remove(function (item) { return item.internalName == internalName });

        }));

    };

    self.addOrderByField = function () {
        self.orderByFields.push(new orderByField(self.availableSortMethods[0], self.availableFields()[0]));
    };

    self.removeOrderByField = function (orderByField) {
        self.orderByFields.remove(orderByField);
    };

    self.addFilter = function () {
        self.filters.push(new filter(self.availableFields()[0], self.operators[0], ""));
    };

    self.removeFilter = function (filter) {
        self.filters.remove(filter);
    };

    self.isSupportedFieldType = function (fieldType) {
        if (fieldType == "Number" ||
                fieldType == "Currency" ||
                fieldType == "Integer" ||
                fieldType == "Counter" ||
                fieldType == "Text" ||
                fieldType == "Hyperlink" ||
                fieldType == "Picture" ||
                fieldType == "Note" ||
                fieldType == "User" ||
                fieldType == "File" ||
                fieldType == "DateTime" ||
                fieldType == "Choice") {
            return true;
        }
        else {
            return false;
        }
    };


    self.isNumericFieldType = function (fieldType) {
        if (
            fieldType == "Number" ||
            fieldType == "Currency" ||
            fieldType == "Integer" ||
            fieldType == "Counter"
        ) {
            return true;
        }
        else {
            return false;
        }


    };

    self.isTextFieldType = function (fieldType) {
        if (
            fieldType == "Text" ||
            fieldType == "File" ||
            fieldType == "Note" ||
            fieldType == "Choice" ||
            fieldType == "Hyperlink" ||
            fieldType == "Picture"
        ) {
            return true;
        }
        else {
            return false;
        }


    };


    self.queryString = ko.computed(function () {
        var select = "";
        var filter = "";
        var orderBy = "";
        var expand = "";
        var query = "";

        var baseUrlHostWeb = self.hostWebUrl + "/_api/web/lists/getbytitle('" + encodeURIComponent($("#selLists option:selected").text()) + "')/items?";
        var baseUrlAppWeb = self.appWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('" + encodeURIComponent($("#selLists option:selected").text()) + "')/items?";


        for (var i = 0; i < self.selectedFields().length; i++) {
            var field = self.selectedFields()[i];
            var selectField = "";
            var expandField = "";

            if (field.type == "User") {
                selectField = field.internalName + "/Name";
                expandField = field.internalName + "/Name";
            }
            else {
                selectField = field.internalName;
            }

            if (select == "")
                select = select + selectField;
            else
                select = select + "," + selectField;

            if (expandField != "") {
                if (expand == "")
                    expand = expand + expandField;
                else
                    expand = expand + "," + expandField;
            }

        }

        for (var i = 0; i < self.orderByFields().length; i++) {
            var orderByField = self.orderByFields()[i];
            var orderByTemp = "";

            if (orderByField.field().type == "User") {
                orderByTemp = orderByField.field().internalName + '/Name';
            }
            else {
                orderByTemp = orderByField.field().internalName;
            }

            if (orderBy == "")
                orderBy = orderBy + orderByTemp + ' ' + orderByField.ascDesc().value;
            else
                orderBy = orderBy + "," + orderByTemp + ' ' + orderByField.ascDesc().value;
        }

        for (var i = 0; i < self.filters().length; i++) {
            var filterField = self.filters()[i];
            var filterTemp = "";

            if (self.isNumericFieldType(filterField.field().type)) {
                filterTemp = filterField.field().internalName + ' ' + filterField.operator().value + ' ' + filterField.value();
            }
            else if (filterField.field().type == "User") {
                if (filterField.operator().value == 'substringof') {
                    filterTemp = "substringOf('" + filterField.value() + "'," + filterField.field().internalName + "/Name)";
                }
                else {
                    filterTemp = filterField.field().internalName + '/Name ' + filterField.operator().value + " '" + filterField.value() + "'";
                }
            }
            else if (self.isTextFieldType(filterField.field().type)) {
                if (filterField.operator().value == 'substringof') {
                    filterTemp = "substringOf('" + filterField.value() + "'," + filterField.field().internalName + ")";
                }
                else {
                    filterTemp = filterField.field().internalName + ' ' + filterField.operator().value + " '" + filterField.value() + "'";
                }
            }

            if (filter == "")
                filter = filterTemp
            else
                filter = filter + " and " + filterTemp;
        }

        if (select != "") {
            query = query + "$select=" + encodeURIComponent(select);
        }
        if (filter != "") {
            query = query + "&$filter=" + encodeURIComponent(filter);
        }
        if (orderBy != "") {
            query = query + "&$orderby=" + encodeURIComponent(orderBy);
        }
        if (expand != "") {
            query = query + "&$expand=" + encodeURIComponent(expand);
        }

        if (self.top() != "" && self.top() > 0) {
            query = query + "&$top=" + encodeURIComponent(self.top());
        }

        if (self.skip() != "" && self.skip() > 0) {
            query = query + "&$skip=" + encodeURIComponent(self.skip());
        }

        self.queryStringFromAppWeb = baseUrlAppWeb + query + "&@target='" + self.hostWebUrl + "'";
        query = baseUrlHostWeb + query;

        if (self.getResults != null) {
            self.getResults();
        }
        return query;
    });

    self.getResults = function () {
        var accept = "";
        var headers = null;

        if (self.format() == "json") {
            headers = { "Accept": "application/json; odata=verbose" };
        }

        self.executor.executeAsync(
            {
                url: self.queryStringFromAppWeb,
                method: "GET",
                headers: headers,
                success: self.getResults_completed,
                error: self.errorHandler
            }
        );
    };


    self.getResults_completed = function (data) {
        
        if (self.format() == "json") {
            
            self.results(htmlEscape( vkbeautify.json(data.body)));
        }
        else {
            self.results(htmlEscape(vkbeautify.xml(data.body)));
        }

         };


    self.errorHandler = function (sender, args) {
        if (args.get_message != null) {
            alert("Error:" + args.get_message());
        }
        else {
            alert("Error occured");
        }
    };
};

function filter(field, operator, value) {
    var self = this;
    self.field = ko.observable(field);
    self.operator = ko.observable(operator);
    self.value = ko.observable(value);
}

function orderByField(ascDesc, field) {
    var self = this;
    self.ascDesc = ko.observable(ascDesc);
    self.field = ko.observable(field);
}

function field(internalName, title, type) {
    var self = this;
    self.internalName = internalName;
    self.title = title;
    self.type = type;
}

function base64Encode(str) {
    var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var out = "", i = 0, len = str.length, c1, c2, c3;
    while (i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if (i == len) {
            out += CHARS.charAt(c1 >> 2);
            out += CHARS.charAt((c1 & 0x3) << 4);
            out += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if (i == len) {
            out += CHARS.charAt(c1 >> 2);
            out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            out += CHARS.charAt((c2 & 0xF) << 2);
            out += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        out += CHARS.charAt(c1 >> 2);
        out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
        out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
        out += CHARS.charAt(c3 & 0x3F);
    }
    return out;
}
function getQuerystring(key, default_) {
    if (default_ == null) default_ = "";
    key = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regex = new RegExp("[\\?&]" + key + "=([^&#]*)");
    var qs = regex.exec(window.location.href);
    if (qs == null)
        return default_;
    else
        return qs[1];
}
function htmlEscape(str) {
    return String(str)
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/ /g, '&nbsp;')
            .replace(/\n/g, '<br />');
}





